package weiyao.xinxidasai.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import weiyao.xinxidasai.DTO.FileTreeNode;
import weiyao.xinxidasai.DTO.Result;
import weiyao.xinxidasai.Utils.FaceToken.FaceCompareUtils;
import weiyao.xinxidasai.Utils.FaceToken.FaceDetection;
import weiyao.xinxidasai.Utils.OSS.deleteUtils;
import weiyao.xinxidasai.Utils.ThreadLocal.UserHolder;
import weiyao.xinxidasai.Utils.OSS.OSSUploader;
import weiyao.xinxidasai.config.Redis.RedisCache;
import weiyao.xinxidasai.mapper.*;
import weiyao.xinxidasai.pojo.FFiles;
import weiyao.xinxidasai.pojo.FilesFolder;
import weiyao.xinxidasai.pojo.Users;
import weiyao.xinxidasai.service.FileService;
import weiyao.xinxidasai.service.FileSystemService;

import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    private final FilesMapper filesMapper;
    private final FolderMapper folderMapper;
    private final VersionMapper versionMapper;
    @Autowired
    private FilesMapper fileMapper;
   @Autowired
    private  deleteUtils deleteUtils;
    @Autowired
    private FileSystemService fileSystemService;
    @Autowired
    private RedisCache redisCache;
    @Value("${upload.path}")
    private String storageBasePath;
    @Autowired
    private OSSUploader ossUploader;
    @Autowired
    private UserMapper userMapper;

    public FileServiceImpl(FilesMapper filesMapper,
                           FolderMapper folderMapper,
                           VersionMapper versionMapper) {
        this.filesMapper = filesMapper;
        this.folderMapper = folderMapper;
        this.versionMapper = versionMapper;
    }


    @PreDestroy
    public void shutdown() {
        executorService.shutdown();
    }







    @Override
    public boolean fileExistsInFolder(String fileName, Long folderId) {
        // 实现逻辑，例如查询数据库
        return filesMapper.existsByFileNameAndFolderId(fileName, folderId);
    }



    @Override
    public Result deleteFile(Long fileId) {
        try {
            // 获取文件信息
            FFiles file = fileMapper.getFileById(fileId);
            if (file == null) {
                return Result.fail("文件不存在");
            }
            Long userId = UserHolder.getUser().getUserId();

            FFiles fileByuserId = fileMapper.getFileByuserId(userId, fileId);
             if (fileByuserId == null) {
                 Result.fail("该文件不属于您或者文件已经删除");
             }
            // 删除数据库记录
            fileMapper.deleteFile(fileId);

            // 删除OSS文件
            deleteUtils.DeleteFile(file.getOssNo());

            return Result.ok("文件删除成功");
        } catch (Exception e) {
            return Result.fail("文件删除失败：" + e.getMessage());
        }
    }

    @Override
    public Result lockFile(Long fileId, String password) {
        // 密码复杂度校验
        if (!password.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+])[A-Za-z\\d!@#$%^&*()_+]{8,}$")) {
            return Result.fail("密码必须包含字母、数字和符号(!@#$%^&*等)，且至少8位");
        }

        // 设置文件锁
        fileMapper.FileLock(fileId, password);

        // 重置尝试次数（添加30分钟过期时间）
        redisCache.setCache("file_attempts:" + fileId, 0, 30, TimeUnit.MINUTES);

        return Result.ok("文件锁定成功");
    }

    @Override
    public Result unlockFile(Long fileId, String password) {
        if ( redisCache.getCache("file_attempts:" + fileId)==null){
            redisCache.setCache("file_attempts:" + fileId, 0, 30, TimeUnit.MINUTES);
        }
        if ( redisCache.getCache("user_attempts:" + UserHolder.getUser().getUserId())==null){
            redisCache.setCache("user_attempts:" + UserHolder.getUser().getUserId(), 0, 30, TimeUnit.MINUTES);
        }

        // 熔断机制检查
        Integer attempts = (Integer) redisCache.getCache("file_attempts:" + fileId);
        Integer userattempt=(Integer)redisCache.getCache("user_attempts:" + UserHolder.getUser().getUserId());
        if (userattempt>30){
            System.out.println("attempts = " + attempts);
            redisCache.setCache(UserHolder.getUser().getUserId()+"lock",true, 60, TimeUnit.MINUTES);
            UserHolder.removeUser();
            return Result.fail("抱歉，该用户暂时锁定");
        }
        if (attempts != null && attempts >= 5) {
            redisCache.increment("user_attempts:" + UserHolder.getUser().getUserId());
            return Result.fail("尝试次数过多，请30分钟后再试");
        }


        // 验证密码
        FFiles file = fileMapper.getFileById(fileId);
        if (file == null || !password.equals(file.getFilesPassword())) {
            // 更新尝试次数
            redisCache.increment("file_attempts:" + fileId);
            redisCache.increment("user_attempts:" + UserHolder.getUser().getUserId());
            return Result.fail("密码错误或文件未上锁");
        }

        // 解锁文件
        fileMapper.FileUnLock(fileId);
        return Result.ok("文件解锁成功");
    }

    @Override
    public Result lockFileFace(Long filesId) {
        Long userId = UserHolder.getUser().getUserId();
        Users byUserId = userMapper.findByUserId(userId);
        boolean empty = byUserId.getSecretKey().isEmpty();
        if (!empty) {
            int i = fileMapper.FileLockByFace(filesId);
            if (i > 0) {
                return Result.ok("人脸上锁成功");
            }else {return Result.fail("未知错误");}

        }
            return Result.fail("抱歉，请在密钥申请处注册人脸信息");
    }

    @Override
    public Result unlockFileWithFace(MultipartFile file, Long fileId) {
        // 1. 用户状态检查
        Long userId = UserHolder.getUser().getUserId();
        Users byUserId = userMapper.findByUserId(userId);
        if (byUserId.getSecretKey() == null) {

            return Result.fail(
                    "未知错误");
        }

        // 2. 文件存在性检查
        FFiles lockedFile = fileMapper.getFileById(fileId);
        if (lockedFile == null) {
            return Result.fail("上锁文件不存在");
        }

        // 3. 文件格式验证
        if (file == null || !file.getOriginalFilename().toLowerCase().endsWith(".jpg")) {
            return Result.fail("请上传有效的JPG格式人脸图片");
        }

        // 4. 尝试次数检查（复用密码解锁的熔断机制）
        String fileAttemptsKey = "file_attempts:" + fileId;
        String userAttemptsKey = "user_attempts:" + UserHolder.getUser().getUserId();

        // 初始化计数器
        if (redisCache.getCache(fileAttemptsKey) == null) {
            redisCache.setCache(fileAttemptsKey, 0, 30, TimeUnit.MINUTES);
        }
        if (redisCache.getCache(userAttemptsKey) == null) {
            redisCache.setCache(userAttemptsKey, 0, 30, TimeUnit.MINUTES);
        }

        // 检查用户尝试次数
        Integer userAttempts = (Integer) redisCache.getCache(userAttemptsKey);
        if (userAttempts != null && userAttempts > 30) {
            redisCache.setCache(UserHolder.getUser().getUserId() + "lock", true, 60, TimeUnit.MINUTES);
            UserHolder.removeUser();
            return Result.fail("用户已被暂时锁定，请60分钟后再试");
        }

        // 检查文件尝试次数
        Integer fileAttempts = (Integer) redisCache.getCache(fileAttemptsKey);
        if (fileAttempts != null && fileAttempts >= 5) {
            redisCache.increment(userAttemptsKey);
            return Result.fail("尝试次数过多，请30分钟后再试");
        }

        File tempFile = null;
        try {
            // 5. 保存临时文件进行人脸检测
            tempFile = File.createTempFile("face_", ".jpg");
            file.transferTo(tempFile);

            // 6. 人脸检测验证
            Map<String, Object> faceResult = FaceDetection.validateFaceDetection(tempFile);

            // 检查人脸数量
            if ("图片中无人脸".equals(faceResult.get("face_num"))) {
                redisCache.increment(fileAttemptsKey);
                redisCache.increment(userAttemptsKey);
                return Result.fail("未检测到人脸，请上传清晰的人脸照片");
            }

            // 检查人脸质量（至少通过7项检测）
            int successCount = (int) faceResult.get("success_count");
            if (successCount < 7) {
                redisCache.increment(fileAttemptsKey);
                redisCache.increment(userAttemptsKey);
                return Result.fail("人脸质量不符合要求，请确保：正面清晰、光照良好、无遮挡");
            }

            // 7. 人脸对比
            String faceToken = (String) faceResult.get("face_token");
            boolean isSamePerson = FaceCompareUtils.compareFace(
                    String.valueOf(UserHolder.getUser().getUserId()),
                    faceToken
            );

            // 8. 处理对比结果
            if (!isSamePerson) {
                redisCache.increment(fileAttemptsKey);
                redisCache.increment(userAttemptsKey);
                return Result.fail("人脸不匹配，解锁失败");
            }

            // 9. 解锁文件
            fileMapper.FileUnLock(fileId);
            return Result.ok("人脸验证成功，文件已解锁");

        } catch (IOException e) {
            log.error("人脸解锁处理失败", e);
            return Result.fail("系统处理异常，请重试");
        } finally {
            // 清理临时文件
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }


    @Override
    public Result renameFile(Long fileId, String newName) {
        try {
            // 参数校验
            if (newName.contains("..") || newName.contains("/")) {
                return Result.fail("文件名包含非法字符");
            }
            FFiles fFiles = fileMapper.selectFileById(fileId);
            List<FFiles> byUserId = fileMapper.findByUserId(UserHolder.getUser().getUserId());
            for (FFiles fFile : byUserId) {
                if (fFile.equals(fFile)) {
                    return Result.fail("文件名重复");
                }
            }


            int result = fileMapper.updateFileName(fileId, newName);
            return result > 0 ? Result.ok("重命名成功") : Result.fail("文件不存在");
        } catch (Exception e) {
            return Result.fail("重命名失败：" + e.getMessage());
        }
    }




    @Override
    public Result moveFile(Long fileId, Long targetFolderId) {
        try {
            // 验证目标文件夹权限
            Long userId = UserHolder.getUser().getUserId();
            FilesFolder filesFolder = folderMapper.selectFolderById(targetFolderId);

            boolean hasPermission =filesFolder.getUserId().equals(userId);
            if (!hasPermission) {
                return Result.fail("无目标文件夹操作权限");
            }

            FFiles file = fileMapper.getFileById(fileId);
            if (file == null) {
                return Result.fail("文件不存在");
            }

            file.setFolderId(targetFolderId);
            int result = fileMapper.updateFileFolder(fileId, targetFolderId);
            return result > 0 ? Result.ok("移动成功") : Result.fail("移动失败");
        } catch (Exception e) {
            return Result.fail("目录更改失败：" + e.getMessage());
        }
    }

    @Override
    public List<FileTreeNode> searchFileTreesByKeyword(Long userId, String keyword) {
        // 1. 获取所有文件夹和文件
        List<FilesFolder> folders = folderMapper.findFolderByUserId(userId);
        List<FFiles> files = fileMapper.findByUserId(userId);

        // 2. 查找匹配的文件（模糊搜索）
        List<FFiles> matchedFiles = files.stream()
                .filter(file -> file.getDisplayName().contains(keyword))
                .collect(Collectors.toList());

        if (matchedFiles.isEmpty()) {
            return Collections.emptyList();
        }

        // 3. 构建完整的文件树（复用原有方法）
        FileTreeNode fullTree = fileSystemService.getUserFileTree(userId);

        // 4. 为每个匹配文件构建从根目录到该文件的路径
        List<FileTreeNode> resultList = new ArrayList<>();

        for (FFiles file : matchedFiles) {
            // 获取文件在完整树中的路径
            List<FileTreeNode> path = findPathToFile(fullTree, file.getFilesId());

            if (!path.isEmpty()) {
                // 创建新的树结构，只包含该文件的路径
                FileTreeNode fileNode = path.get(path.size()-1); // 获取文件节点
                FileTreeNode currentNode = fileNode;

                // 从文件节点向上构建路径
                for (int i = path.size()-2; i >= 0; i--) {
                    FileTreeNode parentNode = path.get(i);
                    FileTreeNode newParent = new FileTreeNode(
                            parentNode.getId(),
                            parentNode.getName(),
                            parentNode.getType(),
                            parentNode.getPath(),
                            parentNode.getFileType()
                    );
                    newParent.getChildren().add(currentNode);
                    currentNode = newParent;
                }

                resultList.add(currentNode);
            }
        }

        return resultList;
    }

    // 辅助方法：在树中查找文件路径
    private List<FileTreeNode> findPathToFile(FileTreeNode root, Long fileId) {
        if (root == null) return Collections.emptyList();

        // 如果是目标文件
        if (root.getType().equals("file") && root.getId().equals(fileId)) {
            return new ArrayList<>(Collections.singletonList(root));
        }

        // 递归搜索子节点
        for (FileTreeNode child : root.getChildren()) {
            List<FileTreeNode> path = findPathToFile(child, fileId);
            if (!path.isEmpty()) {
                path.add(0, root);
                return path;
            }
        }

        return Collections.emptyList();
    }

}